{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "0b41c625",
   "metadata": {},
   "source": [
    "# Probabilistic forecasting\n",
    "\n",
    "When trying to predict future values, most forecasting models try to predict what will be the most likely value. This is called point-forecasting. Although knowing the expected value of a time series in advance is useful in almost any business case, this type of prediction does not provide any information about the confidence of the model or the uncertainty of the prediction.\n",
    "\n",
    "Probabilistic forecasting, as opposed to point-forecasting, is a family of techniques that allow the prediction of the expected distribution of the outcome rather than a single future value. This type of forecasting provides much richer information because it allows the creation of prediction intervals, the range of likely values where the true value may fall. More formally, a prediction interval defines the interval within which the true value of the response variable is expected to be found with a given probability.\n",
    "\n",
    "Skforecast implements several methods for probabilistic forecasting."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4b422d6",
   "metadata": {},
   "source": [
    "### Bootstrapped residuals\n",
    "\n",
    "Bootstrapping is a statistical technique that allows for estimating the distribution of a statistic by resampling the data with replacement. In the context of forecasting, bootstrapping the residuals of a model allows for estimating the distribution of the errors, which can be used to create prediction intervals. Four methods are available in Skforecast for bootstrapping the residuals:\n",
    "\n",
    "+ `predict_bootstrapping`: this method generates multiple forecasting predictions through a bootstrapping process. By sampling from a collection of past observed errors (the residuals), each bootstrapping iteration generates a different set of predictions. The output is a `pandas DataFrame` with one row for each predicted step and one column for each bootstrapping iteration.\n",
    "\n",
    "+ `predict_interval(method='bootstrapping')`: this method estimates quantile prediction intervals using the values generated with `predict_bootstrapping`.\n",
    "\n",
    "+ `predict_quantiles`: this method estimates a list of quantile predictions using the values generated with `predict_bootstrapping`.\n",
    "\n",
    "+ `predict_dist`: this method fits a parametric distribution using the values generated with `predict_bootstrapping`. Any of the continuous distributions available in [scipy.stats](https://docs.scipy.org/doc/scipy/reference/stats.html#continuous-distributions) can be used.\n",
    "\n",
    "The four methods can use in-sample residuals (default) or out-sample residuals. In both cases, the residuals can be conditioned on the predicted value to try to account for the existence of a correlation between the predicted values and the residuals.\n",
    "\n",
    "Discover how to use these methods in [Probabilistic forecasting with bootstrapped residuals](./probabilistic-forecasting-bootstrapped-residuals.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0137385",
   "metadata": {},
   "source": [
    "### Conformal prediction\n",
    "\n",
    "Conformal prediction is a framework for constructing prediction intervals that are guaranteed to contain the true value with a specified probability (coverage probability). It works by combining the predictions of a point-forecasting model with its past residuals—differences between previous predictions and actual values. These residuals help estimate the uncertainty in the forecast and determine the width of the prediction interval that is then added to the point forecast. Skforecast implements Split Conformal Prediction (SCP) through the `predict_interval(method='conformal')` method.\n",
    "\n",
    "Discover how to use conformal methods in [Probabilistic forecasting with conformal prediction](./probabilistic-forecasting-conformal-prediction.html).\n",
    "\n",
    "Conformal methods can also calibrate prediction intervals generated by other techniques, such as quantile regression or bootstrapped residuals. In this case, the conformal method adjusts the prediction intervals to ensure that they remain valid with respect to the coverage probability. Skforecast provides this functionality through the [`ConformalIntervalCalibrator`](../api/preprocessing.html#skforecast.preprocessing.preprocessing.ConformalIntervalCalibrator) transformer.\n",
    "\n",
    "Discover how to perform this calibration in [Probabilistic forecasting, conformal calibration](./probabilistic-forecasting-conformal-calibration.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e211c005",
   "metadata": {},
   "source": [
    "<div class=\"admonition note\" name=\"html-admonition\" style=\"background: rgba(255,145,0,.1); padding-top: 0px; padding-bottom: 6px; border-radius: 8px; border-left: 8px solid #ff9100; border-color: #ff9100; padding-left: 10px; padding-right: 10px\">\n",
    "\n",
    "<p class=\"title\">\n",
    "    <i style=\"font-size: 18px; color:#ff9100; border-color: #ff1744;\"></i>\n",
    "    <b style=\"color: #ff9100;\"> <span style=\"color: #ff9100;\">&#9888;</span> Warning</b>\n",
    "</p>\n",
    "\n",
    "There are several well-established <a href=\"https://mapie.readthedocs.io/en/stable/theoretical_description_regression.html\" target=\"_blank\">methods for conformal prediction</a>, each with its own characteristics and assumptions. However, when applied to time series forecasting, their coverage guarantees are only valid for one-step-ahead predictions. For multi-step-ahead predictions, the coverage probability is not guaranteed. Skforecast implements Split Conformal Prediction (SCP) due to its simplicity and efficiency. \n",
    "\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e920ab6b",
   "metadata": {},
   "source": [
    "### Quantile regression\n",
    "\n",
    "Quantile regression is a technique for estimating the conditional quantiles of a response variable. By combining the predictions of two quantile estimators, an interval can be constructed, with each model estimating one of the bounds of the interval. For example, models trained on $Q = 0.1$ and $Q = 0.9$ produce an 80% prediction interval ($90\\% - 10\\% = 80\\%$).\n",
    "\n",
    "If a machine learning algorithm capable of modeling quantiles is used as the `estimator` in a forecaster, the `predict` method will return predictions for a specified quantile. By creating two forecasters, each configured with a different quantile, their predictions can be combined to generate a prediction interval.\n",
    "\n",
    "Discover how to use this method in [Probabilistic forecasting with quantile regression](./probabilistic-forecasting-quantile-regression.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71f71dca",
   "metadata": {},
   "source": [
    "### Which Method to Use?\n",
    "\n",
    "There is no definitive answer to this question, as the resulting coverage may vary depending on the dataset and estimator. However, some general guidelines can be followed:\n",
    "\n",
    "- **Bootstrapped residuals**: This method achieves good results in most cases, especially when using residuals conditioned on the predicted value (`use_binned_residuals = True`). However, it is computationally expensive, especially when using a large number of bootstrapping iterations, and may not scale well to large datasets or multiple time series.\n",
    "\n",
    "- **Conformal Prediction**: Similar results to bootstrapping, but more computationally efficient (fast).\n",
    "\n",
    "- **Quantile regression**: An appropriate choice when the estimator is capable of modeling quantiles. However, two Forecasters must be trained — one for each quantile — which can be computationally expensive.\n",
    "\n",
    "None of these methods guarantee coverage probability for multi-step predictions. Therefore, it is strongly recommended to validate the empirical coverage obtained with the chosen method. If the coverage is not satisfactory, the prediction intervals can be calibrated using the [`ConformalIntervalCalibrator`](../api/preprocessing.html#skforecast.preprocessing.preprocessing.ConformalIntervalCalibrator) transformer.\n",
    "\n",
    "For bootstrapped and conformal methods, it is recommended to use out-sample residuals (known as calibration residuals in conformal literature) as they provide a more realistic estimate of the prediction uncertainty (`use_in_sample_residuals = False`). If in-sample residuals are used, the prediction intervals may be too narrow, resulting in low coverage."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "562eb504",
   "metadata": {},
   "source": [
    "<div class=\"admonition note\" name=\"html-admonition\" style=\"background: rgba(255,145,0,.1); padding-top: 0px; padding-bottom: 6px; border-radius: 8px; border-left: 8px solid #ff9100; border-color: #ff9100; padding-left: 10px; padding-right: 10px\">\n",
    "\n",
    "<p class=\"title\">\n",
    "    <i style=\"font-size: 18px; color:#ff9100; border-color: #ff1744;\"></i>\n",
    "    <b style=\"color: #ff9100;\"> <span style=\"color: #ff9100;\">&#9888;</span> Warning</b>\n",
    "</p>\n",
    "\n",
    "As Rob J Hyndman explains in his <a href=\"https://robjhyndman.com/hyndsight/narrow-pi/\">blog</a>, in real-world problems, almost all prediction intervals are too narrow. For example, nominal 95% intervals may only provide coverage between 71% and 87%. This is a well-known phenomenon and arises because they do not account for all sources of uncertainty. With forecasting models, there are at least four sources of uncertainty:\n",
    "\n",
    "<ul>\n",
    "  <li>The random error term</li>\n",
    "    \n",
    "  <li>The parameter estimates</li>\n",
    "    \n",
    "  <li>The choice of model for the historical data</li>\n",
    "    \n",
    "  <li>The continuation of the historical data generating process into the future</li>\n",
    "</ul>\n",
    "\n",
    "When producing prediction intervals for time series models, generally only the first of these sources is taken into account. Therefore, it is advisable to use test data to validate the empirical coverage of the interval and not only rely on the expected one.\n",
    "\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d2f26236",
   "metadata": {},
   "source": [
    "<div class=\"admonition note\" name=\"html-admonition\" style=\"background: rgba(0,191,191,.1); padding-top: 0px; padding-bottom: 6px; border-radius: 8px; border-left: 8px solid #00bfa5; border-color: #00bfa5; padding-left: 10px; padding-right: 10px;\">\n",
    "\n",
    "<p class=\"title\">\n",
    "    <i style=\"font-size: 18px; color:#00bfa5;\"></i>\n",
    "    <b style=\"color: #00bfa5;\">&#128161 Tip</b>\n",
    "</p>\n",
    "\n",
    "<p>For more examples on how to use probabilistic forecasting, check out the following articles:</p>\n",
    "<ul>\n",
    "    <li>\n",
    "        <a href=\"https://cienciadedatos.net/documentos/py42-probabilistic-forecasting\" target=\"_blank\">\n",
    "            Probabilistic forecasting with machine learning\n",
    "        </a>\n",
    "    </li>\n",
    "    <li>\n",
    "        <a href=\"https://cienciadedatos.net/documentos/py60-probabilistic-forecasting-prediction-intervals-multi-step-forecasting\" target=\"_blank\">\n",
    "            Probabilistic forecasting: prediction intervals for multi-step time series forecasting\n",
    "        </a>\n",
    "    </li>\n",
    "    <li>\n",
    "        <a href=\"../faq/probabilistic-forecasting-crps-score.html\" target=\"_blank\">\n",
    "            Continuous Ranked Probability Score (CRPS) in probabilistic forecasting\n",
    "        </a>\n",
    "    </li>\n",
    "</ul>\n",
    "\n",
    "</div>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "skforecast_py12",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.11"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
